/*
 * EsferaDeformada.cpp
 *
 *  Created on: 21/10/2013
 *      Author: ezequiel
 */

#include "EsferaDeformada.h"
#define CANT_PUNTOS 16
#define CANT_CURVAS_DIRECCION 2
#define ALTURA 10
EsferaDeformada::EsferaDeformada() {
	this->esferaF_vertex_buffer_size = ALTURA * CANT_CURVAS_DIRECCION * CANT_PUNTOS  * 3;
	this->esferaF_normal_buffer_size =ALTURA * CANT_CURVAS_DIRECCION * CANT_PUNTOS  * 3;
//	this->esferaF_index_buffer_size = ALTURA * ALTURA * CANT_CURVAS_DIRECCION * CANT_PUNTOS ;
//	this->esferaF_index_buffer_size = ALTURA * 2 * CANT_PUNTOS +   2 * CANT_PUNTOS * (ALTURA-2) ;
//	this->esferaF_index_buffer_size = 570;
	this->esferaF_index_buffer_size = 380;
	this->esferaF_vertex_buffer = new GLfloat[this->esferaF_vertex_buffer_size];
	this->esferaF_normal_buffer = new GLfloat[this->esferaF_normal_buffer_size];
	this->esferaF_texture_buffer = new GLfloat[this->esferaF_vertex_buffer_size * 2 / 3];
	this->esferaF_index_buffer = new GLuint[this->esferaF_index_buffer_size];
	this->crearForma();
}

void EsferaDeformada::crearForma() {
	glm::vec3 vect;
	CurvaBessier* curvaS;
	std::vector<glm::vec3> curvaA;
	std::vector<glm::vec3> curvaB;
	std::vector <glm::vec3> curvaZ;
	//////// curva de forma A  ///////


	vect = glm::vec3(0.0f, 0.0f , 0.0f);
	curvaA.push_back(vect);
	vect = glm::vec3(5.0f, 9.0f , 0.0f);
	curvaA.push_back(vect);
	vect = glm::vec3(10.0f, 13.0f, 0.0f);
	curvaA.push_back(vect);
	vect = glm::vec3(15.0f, 0.0f , 0.0f);
	curvaA.push_back(vect);
	curvaS = new CurvaBessier(curvaA, CANT_PUNTOS - 1);
	curvaA = curvaS->obtenerPuntos();


	//////// curva de forma B  ///////
	vect = glm::vec3(15.0f, 0.0f , 0.0f);
	curvaB.push_back(vect);
	vect = glm::vec3(10.0f, -9.0f , 0.0f);
	curvaB.push_back(vect);
	vect = glm::vec3(5.0f, -13.0f, 0.0f);
	curvaB.push_back(vect);
	vect = glm::vec3(0.0f, 0.0f , 0.0f);
	curvaB.push_back(vect);
	curvaS = new CurvaBessier(curvaB, CANT_PUNTOS - 1);
	curvaB = curvaS->obtenerPuntos();

	/////////// curva en z /////////////


	vect = glm::vec3(0.0f, 0.0f , 0.0f);
	curvaZ.push_back(vect);
	vect = glm::vec3(0.0f, 0.0f , 3.0f);
	curvaZ.push_back(vect);
	vect = glm::vec3(0.0f, 0.0f, 5.0f);
	curvaZ.push_back(vect);
	vect = glm::vec3(0.0f, 0.0f , 7.0f);
	curvaZ.push_back(vect);
	curvaS = new CurvaBessier(curvaZ, ALTURA - 1);
	curvaZ = curvaS->obtenerPuntos();


	///////// curva ancho /////////////

		std::vector<glm::vec3> vecGrosor;
    	vect = glm::vec3(0.05f, 5.0f , 0.0f);
    	vecGrosor.push_back(vect);
    	vect = glm::vec3(0.20f, 10.0f , 0.0f);
    	vecGrosor.push_back(vect);
    	vect = glm::vec3(0.30f, 15.0 , 0.0f);
    	vecGrosor.push_back(vect);
    	vect = glm::vec3(0.05f, 20.0f , 0.0f);
    	vecGrosor.push_back(vect);
    	CurvaBessier* curvaGrosor = new CurvaBessier(vecGrosor,ALTURA - 1 );
    	vecGrosor = curvaGrosor->obtenerPuntos();

	//////////////// variables //////////////////
   	 float pasoU = 0;
   		    float pasoV = 0;
   		    int p = 0;
	int j ;
	int k;
	int z = 0 ;
	int i;
		 /////////// puntos ///////////////
	for (z= 0; z < ALTURA; z++){
			j= 0;
			pasoU = 0;
			pasoV = pasoV + 0.05;
		    	for( i = 6 * CANT_PUNTOS * z  ;i <  3  * CANT_PUNTOS + 6 * CANT_PUNTOS * z; i = i + 3)
		    		    	{
		    		    		this->esferaF_vertex_buffer[i] = (curvaA[j].x + curvaZ[z].x) * vecGrosor[z].x    ;
		    		    		this->esferaF_vertex_buffer[i+1] = ( curvaA[j].y + curvaZ[z].y  ) * vecGrosor[z].x   ;
		    		    		this->esferaF_vertex_buffer[i+2] = (curvaA[j].z + curvaZ[z].z )  ;
		    		    		this->esferaF_normal_buffer[i] = 0.15f;
		    		    		this->esferaF_normal_buffer[i+1] = 0.15f;
		    		    		this->esferaF_normal_buffer[i+2] = 0.15f;
		    		    		this->esferaF_texture_buffer[p] = pasoU;
		    		    		p++;
		    		    		this->esferaF_texture_buffer[p] = pasoV;
		    		    		 p++;
		    		    		pasoU = pasoU + 0.1 ;
//		    		    			    		this->esferaF_index_buffer[i] = j + 2 * z * CANT_PUNTOS;
//		    		    			    		this->esferaF_index_buffer[i+1] = j + 2 * z * CANT_PUNTOS;
//		    		    			    		this->esferaF_index_buffer[i+2] = j + 2 *  z * CANT_PUNTOS;
		    		    			    		j++;
		    		    	}
//	}

		    	 pasoU = 0;
		    	 k = j;
		    	 j= 0;
//		for (int z = 0 ; z < ALTURA ; z++  ){
		    		    	for( i = 3 * CANT_PUNTOS +  6 * CANT_PUNTOS * z ;i < 6 * CANT_PUNTOS + z * CANT_PUNTOS * 6; i = i + 3)
		    		    		    {
		    		    		    	this->esferaF_vertex_buffer[i] = (curvaB[j].x + curvaZ[z].x)  * vecGrosor[z].x      ;
		    		    		    	this->esferaF_vertex_buffer[i+1] = ( curvaB[j].y   + curvaZ[z].y ) * vecGrosor[z].x    ;
		    		    		    	this->esferaF_vertex_buffer[i+2] = (curvaB[j].z  + curvaZ[z].z )  ;
				    		    		this->esferaF_texture_buffer[p] = pasoU;
				    		    		p++;
				    		    		this->esferaF_texture_buffer[p] = pasoV;
				    		    		 p++;
					    		    		pasoU = pasoU + 0.1 ;
//		    		    		    	this->esferaF_normal_buffer[i] = 0.15f;
//		    		    		    	this->esferaF_normal_buffer[i+1] = 0.15f;
//		    		    		    	this->esferaF_normal_buffer[i+2] = 0.15f;
//		    		    		    	this->esferaF_index_buffer[i] = k + 2 *z *CANT_PUNTOS;
//		    		    		    	this->esferaF_index_buffer[i+1] = k + 2 *z * CANT_PUNTOS ;
//		    		    		    	this->esferaF_index_buffer[i+2] = k + 2 * z * CANT_PUNTOS;
		    		    		    			    		j++;
		    		    		    			    		k++;
		    		    		    	}
//
//
				}

//		this->indexar();
	this->calcularNormales();
	this->indexarPuntos();


}

EsferaDeformada::~EsferaDeformada() {
	delete this->esferaF_vertex_buffer;
	delete this->esferaF_normal_buffer;
	delete this->esferaF_index_buffer;
	delete this->esferaF_texture_buffer;
}

void EsferaDeformada::render(GLuint handle, glm::mat4* matModelo) {
	this->renderMatrix(handle, &proyeccion);
//	glBindTexture (GL_TEXTURE_2D, this->textureid);

	// Bind Light Settings
			// ###################

	glm::vec3 light_intensity = glm::vec3(0.0f, 0.0f, 1.0f);
	glm::vec4 light_position = glm::vec4(1.0f, 1.0f, 1.0f, 1.0f);
	glm::vec3 La = glm::vec3(0.5f, 0.2f, 0.1f);
	glm::vec3 Ld = glm::vec3(1.0f, 1.0f, 1.0f);
	glm::vec3 Ls = glm::vec3(0.1f, 1.0f, 0.6f);
	glm::vec3 Ka = glm::vec3(0.3f, 0.3f, 0.3f);
	glm::vec3 Kd = glm::vec3(0.7f, 0.7f, 0.7f);
	glm::vec3 Ks = glm::vec3(0.7f, 0.7f, 0.7f);
	float Shininess = 0.5;

			// Light Intensity
			GLuint location_light_intensity = glGetUniformLocation(handle,
				"LightIntensity");

			if(location_light_intensity >= 0)
				glUniform4fv( location_light_intensity, 1, &light_intensity[0]);

			// Light Position
			GLuint location_light_position = glGetUniformLocation(handle,
				"LightPosition");

			if(location_light_position >= 0)
				glUniform4fv( location_light_position, 1, &light_position[0]);

			// La
			GLuint location_la = glGetUniformLocation(
				handle, "La");

			if(location_la >= 0)
				glUniform3fv( location_la, 1, &La[0]);

			// Ld
			GLuint location_ld = glGetUniformLocation(
				handle, "Ld");

			if(location_ld >= 0)
				glUniform3fv( location_ld, 1, &Ld[0]);

			// Ls
			GLuint location_ls = glGetUniformLocation(
				handle, "Ls");

			if(location_ls >= 0)
				glUniform3fv( location_ls, 1, &Ls[0]);


			// Ka
			GLuint location_ka = glGetUniformLocation(
				handle, "Ka");

			if(location_ka >= 0)
				glUniform3fv( location_ka, 1, &Ka[0]);

			// Kd
			GLuint location_kd = glGetUniformLocation(
				handle, "Kd");

			if(location_kd >= 0)
				glUniform3fv( location_kd, 1, &Kd[0]);

			// Ks
			GLuint location_ks = glGetUniformLocation(
				handle, "Ks");

			if(location_ks >= 0)
				glUniform3fv( location_ks, 1, &Ks[0]);


			// Shininess
			GLfloat location_shininess = glGetUniformLocation(handle,
				"Shininess");

			if(location_shininess >= 0)
				glUniform1f(location_shininess, Shininess);

			    glm::mat3 normal_matrix = glm::mat3 ( 1.0f );

			    // Bind Normal MAtrix
			    GLuint location_normal_matrix = glGetUniformLocation(handle, "NormalMatrix");
			    if( location_normal_matrix >= 0 )
				{
			        glUniformMatrix3fv( location_normal_matrix, 1, GL_FALSE, &normal_matrix[0][0]);
				}

			    // Bind Model Matrix
			    GLuint location_model_matrix = glGetUniformLocation( handle, "ModelMatrix");
			    if( location_model_matrix >= 0 )
				{
					glUniformMatrix4fv( location_model_matrix, 1, GL_FALSE,&((*matModelo)[0][0]));
				}
//			    int loc = glGetUniformLocation(handle, "Tex1");
//			       				    if( loc >= 0 )
//			       				    {
//			       						// We indicate that Uniform Variable sampler2D "text" uses  Texture Unit 0
//			       				        glUniform1i(loc, 0);
//			       				    }
//			       				    else
//			       				    {
//			       				        fprintf(stderr, "Uniform variable Tex1 not founddd!\n");
//			       				    }

			    glActiveTexture(GL_TEXTURE0);
			    glEnable(GL_TEXTURE_2D);
			    int loc = glGetUniformLocation(handle, "Tex1");
			    glUniform1i(loc, 0);
			    glBindTexture(GL_TEXTURE_2D, this->textureid);

			    if(this->textureNormalId != 0){
			    glActiveTexture(GL_TEXTURE1);
			    glEnable(GL_TEXTURE_2D);
			    int loc1 = glGetUniformLocation(handle, "NormalMapTex");
			    glUniform1i(loc1, 1);
			    glBindTexture(GL_TEXTURE_2D, this->textureNormalId);  }


	//		    glClearColor(20,20,0,0);
			    glEnableClientState(GL_VERTEX_ARRAY);
				glEnableClientState(GL_NORMAL_ARRAY);
				glEnableClientState(GL_TEXTURE_COORD_ARRAY);
				glVertexPointer(3, GL_FLOAT, 0,esferaF_vertex_buffer);
				glNormalPointer(GL_FLOAT, 0, esferaF_normal_buffer);
				glTexCoordPointer(2, GL_FLOAT, 0, esferaF_texture_buffer);
			    glDrawElements(GL_TRIANGLE_STRIP, this->esferaF_index_buffer_size, GL_UNSIGNED_INT, this->esferaF_index_buffer);
			    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
			    glDisableClientState(GL_VERTEX_ARRAY);
			    glDisableClientState(GL_NORMAL_ARRAY);
}

void EsferaDeformada::indexar(){
int malla[32][10];

	        int e = 0;
	        for(int m = 0; m < 32; m++)
	                for(int n = 0; n < 10; n++)
	                        malla[m][n] = e++;


	        int sentido = 1;
	        int k = 0;

	        for(int i=0; i < (31); i++)
	        {
	                if(sentido == 1)
	                {
	                        for(int j=0; j <= (9); j++) {
	                                this->esferaF_index_buffer[k++] = malla[i][j];
	                                this->esferaF_index_buffer[k++] = malla[i+1][j];
	                        }

	                        sentido = -1;
	                }
	                else if(sentido == -1)
	                {
	                        for(int j=(9); j >= 0; j--) {
	                                this->esferaF_index_buffer[k++] = malla[i][j];
	                                this->esferaF_index_buffer[k++] = malla[i+1][j];
	                        }

	                        sentido = 1;
	                }
	        }

}

void EsferaDeformada::indexarPuntos() {
	int e = 0;
for (int k = 0 ; k < 20 ; k++){
	for (int i = k * CANT_PUNTOS  ; i < k * CANT_PUNTOS + CANT_PUNTOS ; i = i +2 )
	{
		this->esferaF_index_buffer[i] = e ;
		e++;
		this->esferaF_index_buffer[i+1] = e + 2*CANT_PUNTOS;
		e++;
	}
}
}


void EsferaDeformada::calcularNormales() {
//	int e = 0;
	glm::vec3 vecResult;
	glm::vec3 vec1;
	glm::vec3 vec2;

for (int k = 0 ; k < ALTURA - 1 ; k++){
	for (int i = k * CANT_PUNTOS * 3 ; i < k * CANT_PUNTOS * 3 + CANT_PUNTOS * 3 ; i = i +3 )
	{
		vec1.x = esferaF_vertex_buffer[i] - esferaF_vertex_buffer[i+6*CANT_PUNTOS];
		vec1.y = esferaF_vertex_buffer[i+1] - esferaF_vertex_buffer[i+6*CANT_PUNTOS+1];
		vec1.z = esferaF_vertex_buffer[i+2] - esferaF_vertex_buffer[i+6*CANT_PUNTOS+2];
		vec2.x = esferaF_vertex_buffer[i] - esferaF_vertex_buffer[i+3];
		vec2.y = esferaF_vertex_buffer[i+1] -esferaF_vertex_buffer[i+4];
		vec2.z = esferaF_vertex_buffer[i+2] -esferaF_vertex_buffer[i+5];
		vecResult = calcularNormal(vec1, vec2);
		esferaF_normal_buffer[i] = vecResult.x;
		esferaF_normal_buffer[i+1] = vecResult.y;
		esferaF_normal_buffer[i+2] = vecResult.z;

	}
}
}

void EsferaDeformada::render(GLuint handle) {
}

glm::vec3 EsferaDeformada::calcularNormal(glm::vec3 vec1, glm::vec3 vec2) {
	glm::vec3 retorno;
	retorno.x = vec1.y * vec2.z - vec1.z * vec2.y;
	retorno.y = vec1.z * vec2.x - vec1.x * vec2.z;
	retorno.z =vec1.x * vec2.y - vec1.y * vec2.x;


	return retorno;
}
